package com.alipay.rebate.shop.service.customer.impl;

import com.alipay.rebate.shop.constants.*;
import com.alipay.rebate.shop.dao.mapper.CouponGetRecordMapper;
import com.alipay.rebate.shop.dao.mapper.EntitySettingsMapper;
import com.alipay.rebate.shop.dao.mapper.LuckyMoneyCouponMapper;
import com.alipay.rebate.shop.dao.mapper.UserIncomeMapper;
import com.alipay.rebate.shop.dao.mapper.UserMapper;
import com.alipay.rebate.shop.dao.mapper.WithDrawMapper;
import com.alipay.rebate.shop.exceptoin.AlipayAccountNotBoundException;
import com.alipay.rebate.shop.exceptoin.AmountNotEnougthException;
import com.alipay.rebate.shop.exceptoin.BusinessException;
import com.alipay.rebate.shop.exceptoin.UitNotEnougthException;
import com.alipay.rebate.shop.helper.LuckyMoneyHelper;
import com.alipay.rebate.shop.model.EntitySettings;
import com.alipay.rebate.shop.model.User;
import com.alipay.rebate.shop.model.UserIncome;
import com.alipay.rebate.shop.model.WithDraw;
import com.alipay.rebate.shop.pojo.entitysettings.WithDrawSettings;
import com.alipay.rebate.shop.pojo.user.customer.UserMiddleModel;
import com.alipay.rebate.shop.pojo.user.customer.UserWithdrawResponse;
import com.alipay.rebate.shop.service.customer.CustomerWithdrawService;
import com.alipay.rebate.shop.utils.DateUtil;
import com.alipay.rebate.shop.utils.DecimalUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.apache.tomcat.util.http.fileupload.disk.DiskFileItem;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@Transactional
public class CustomerWithdrawServiceImpl implements
    CustomerWithdrawService {

  private Logger logger = LoggerFactory.getLogger(CustomerWithdrawServiceImpl.class);

  private ObjectMapper objectMapper = new ObjectMapper();

  @Resource
  private UserMapper userMapper;
  @Resource
  private UserIncomeMapper userIncomeMapper;
  @Resource
  private WithDrawMapper withDrawMapper;
  @Resource
  private EntitySettingsMapper entitySettingsMapper;

  @Override
  public PageInfo<WithDraw> selectUserAmWithDraw(Long userId,Integer pageNo, Integer pageSize) {
    logger.debug("userId is: {}",userId);
    PageHelper.startPage(pageNo,pageSize);
    List<WithDraw> withDraws =  withDrawMapper.selectWithDrawByUserIdAndType(userId,
        WithDrawConstant.WITHDRAW_AMOUNT_TYPE);
    PageInfo<WithDraw> pageInfo = new PageInfo<>(withDraws);
    return pageInfo;
  }

  @Override
  public PageInfo<WithDraw> selectUserUitWithDraw(Long userId,Integer pageNo, Integer pageSize) {
    logger.debug("userId is: {}",userId);
    PageHelper.startPage(pageNo,pageSize);
    List<WithDraw> withDraws = withDrawMapper.selectWithDrawByUserIdAndType(userId,
        WithDrawConstant.WITHDRAW_UIT_TYPE);
    PageInfo<WithDraw> pageInfo = new PageInfo<>(withDraws);
    return pageInfo;
  }

  @Override
  public PageInfo<WithDraw> selectUserWithDraw(Long userId, Integer pageNo, Integer pageSize) {
    logger.debug("userId is: {}",userId);
    PageHelper.startPage(pageNo,pageSize);
    List<WithDraw> withDraws = withDrawMapper.selectWithDrawByUserId(userId);
    PageInfo<WithDraw> pageInfo = new PageInfo<>(withDraws);
    return pageInfo;
  }

  @Override
  public UserWithdrawResponse withdrawAmount(WithDraw withDraw){
    logger.debug("userId is : {}",withDraw);
    User user = userMapper.selectById(withDraw.getUserId());
    logger.debug("user is : {}",user);
    // 检查支付宝号是否绑定
    if(StringUtils.isEmpty(user.getAlipayAccount())){
      throw new BusinessException("支付宝账号未绑定",StatusCode.ALIPAY_ACCOUNT_NOT_BIND);
    }
    // 查看用户是否有条件提现余额
    checkIfUserCanWithDrawAM(user,withDraw);
    // 减少用户金额
    userMapper.plusOrReductVirtualMoneyDirectly(
        null,null,withDraw.getMoney().negate()
        ,user.getUserId()
    );
    // 插入提现记录
    insertWithDrawRecord(withDraw,user,
        WithDrawConstant.WITHDRAW_ONGOING,
        WithDrawConstant.WITHDRAW_AMOUNT_TYPE);

    insertUserIncome(withDraw);

    // 查找此用户当前提现详情
    return selectWithDrawDetailForCustomer(user.getUserId());
  }

  @Override
  public UserWithdrawResponse withdrawUit(WithDraw withDraw){

    User user = userMapper.selectById(withDraw.getUserId());
    // 检查支付宝号是否绑定
    if(StringUtils.isEmpty(user.getAlipayAccount())){
      throw new BusinessException("支付宝账号未绑定",StatusCode.ALIPAY_ACCOUNT_NOT_BIND);
    }
    logger.debug("User is : {}",user);
    // 查看用户是否有权限提现集分宝
    checkIfUserCanWithDrawUit(user,withDraw);
    // 减少用户集分宝
    userMapper.plusOrReductVirtualMoneyDirectly(
        - DecimalUtil.convertMoneyToUit(withDraw.getMoney()),
        null,null,user.getUserId()
    );
    // 插入提现记录
    insertWithDrawRecord(withDraw,user,
        WithDrawConstant.WITHDRAW_ONGOING,
        WithDrawConstant.WITHDRAW_UIT_TYPE);

    insertUserIncome(withDraw);

    return selectWithDrawDetailForCustomer(user.getUserId());
  }

  private void insertUserIncome(WithDraw withDraw){
    try {
      //往用户收益表添加记录
      logger.debug("insert user_income");
      UserIncome userIncome = buildUserIncome(withDraw);
      userIncomeMapper.insert(userIncome);
    }catch (Exception e){
      e.printStackTrace();
    }
  }

  private void checkIfUserCanWithDrawUit(User user,WithDraw withDraw)  {
    // 查看是否有正在处理的订单
    checkIfExistsWithOngoingBefore(withDraw,user);
    // 获取体现中的金额
    UserMiddleModel userMiddleModel = withDrawMapper.selectWithDrawDetailForCustomer(user.getUserId());
    logger.debug("ongoing uit money:{}",userMiddleModel.getWithdrawUITOnGoing());
    long withDrawUit = withDraw.getMoney().multiply(new BigDecimal(UserContant.UIT_BASE)).longValue();
    long canWithDrawUit = user.getUserIntgeralTreasure() -
        userMiddleModel.getWithdrawUITOnGoing()
            .multiply(new BigDecimal(UserContant.UIT_BASE)).longValue();
    if(canWithDrawUit < withDrawUit){
      throw new UitNotEnougthException();
    }
    WithDrawSettings withDrawSettings = getWithDrawSettings();
    if(withDrawSettings == null){
      return ;
    }
    logger.debug("WithDrawSettings is :{}",withDrawSettings);
    if(withDrawSettings.getTaobaoMinWUit() != null){
      // 最小金额
      if(withDrawUit < withDrawSettings.getTaobaoMinWUit()){
        throw new BusinessException("提现的集分宝数目不能小于"+withDrawSettings.getTaobaoMinWUit(),
            StatusCode.INTERNAL_ERROR);
      }
      // 最小倍数
      long multiple = withDrawSettings.getUitMinMutiple();
      long temp = withDrawUit - withDrawSettings.getTaobaoMinWUit();
      if(temp % multiple != 0){
        throw new BusinessException("最小倍数为"+withDrawSettings.getUitMinMutiple(),
            StatusCode.INTERNAL_ERROR);
      }
      // 提现时间
      checkTime(withDrawSettings);
    }
  }

  private void checkIfUserCanWithDrawAM(User user,WithDraw withDraw){
    // 查看是否有正在处理的订单
    checkIfExistsWithOngoingBefore(withDraw,user);
    // 获取体现中的金额
    UserMiddleModel userMiddleModel = withDrawMapper.selectWithDrawDetailForCustomer(user.getUserId());
    logger.debug("ongoing am money:{}",userMiddleModel.getWithdrawAMOnGoing());
    // 计算可提取金额
    BigDecimal canWithDrawMoney = user.getUserAmount().subtract(
        new BigDecimal(userMiddleModel.getWithdrawAMOnGoing())
    );
    logger.debug("canWithDrawMoney : {}",canWithDrawMoney);
    if(canWithDrawMoney.compareTo(withDraw.getMoney()) < 0){
      throw new AmountNotEnougthException();
    }
    EntitySettings entitySettings = entitySettingsMapper.selectByType(
        EntitySettingsConstant.WITHDRAW_SETTINGS_TYPE);
    logger.debug("EntitySettings is :{}",entitySettings);
    if(entitySettings == null){
      return;
    }
    WithDrawSettings withDrawSettings = getWithDrawSettings();
    if(withDrawSettings == null){
      return ;
    }
    logger.debug("WithDrawSettings is :{}",withDrawSettings);
    if(withDrawSettings.getTaobaoMinWUit() != null){
      // 最小金额
      if(withDraw.getMoney().compareTo(withDrawSettings.getMinWAmount()) <0){
        throw new BusinessException("提现金额最低为"+withDrawSettings.getMinWAmount(),
            StatusCode.INTERNAL_ERROR);
      }
      // 最小倍数
      BigDecimal multiple = new BigDecimal(withDrawSettings.getAmMinMutiple());
      BigDecimal temp = withDraw.getMoney().subtract(withDrawSettings.getMinWAmount());
      BigDecimal[] d = temp.divideAndRemainder(multiple);
      if(d[1].compareTo(new BigDecimal(0)) != 0){
        throw new BusinessException("最小倍数为"+withDrawSettings.getAmMinMutiple(),
            StatusCode.INTERNAL_ERROR);
      }
      // 提现时间
      checkTime(withDrawSettings);
    }
  }

  private WithDrawSettings getWithDrawSettings(){
    EntitySettings entitySettings = entitySettingsMapper.selectByType(
        EntitySettingsConstant.WITHDRAW_SETTINGS_TYPE);
    logger.debug("EntitySettings is :{}",entitySettings);
    if(entitySettings == null){
      return null;
    }
    String jsonStr = entitySettings.getJson();
    try {
      return objectMapper.readValue(jsonStr,WithDrawSettings.class);
    } catch (IOException ex) {
      logger.error(""+ex);
    }
    return null;
  }

  private void checkIfExistsWithOngoingBefore(WithDraw withDraw, User user){
    if(StringUtils.isEmpty(user.getAlipayAccount())){
      throw new AlipayAccountNotBoundException();
    }
    int count = withDrawMapper.selectCountByStatusUserId(withDraw.getUserId(),WithDrawConstant.WITHDRAW_ONGOING);
    if(count >0){
      throw new BusinessException("您有"+count+"笔提现正在处理", StatusCode.WITH_DRAW_ERROR);
    }
  }

  private void checkTime(WithDrawSettings withDrawSettings){
    // 提现时间
    LocalDateTime localDateTime = LocalDateTime.now();
    // 如果时间配置为空，那么直接返回
    if(withDrawSettings.getTimeStart() == null && withDrawSettings.getTimeEnd() == null){
      return;
    }
    int date = localDateTime.getDayOfMonth();
    logger.debug("date is : {}",date);
    if(withDrawSettings.getTimeStart() != null && withDrawSettings.getTimeEnd() != null){
      if(!(date >= withDrawSettings.getTimeStart() && date<= withDrawSettings.getTimeEnd())){
        throw new BusinessException("提现时间为每月"+withDrawSettings.getTimeStart()+"号到"+
            withDrawSettings.getTimeEnd()+"号",
            StatusCode.INTERNAL_ERROR);
      }
    }
    if(withDrawSettings.getTimeStart() != null){
      if(date < withDrawSettings.getTimeStart()){
        throw new BusinessException("提现时间为每月"+withDrawSettings.getTimeStart()+"号之后",
            StatusCode.INTERNAL_ERROR);
      }
    }
    if(withDrawSettings.getTimeEnd() != null){
      if(date> withDrawSettings.getTimeEnd()){
        throw new BusinessException("提现时间为每月"+withDrawSettings.getTimeEnd()+"号之前",
            StatusCode.INTERNAL_ERROR);
      }
    }
  }

  private void insertWithDrawRecord(
      WithDraw withDraw,
      User user,
      Integer status,
      Integer type
  ){
    //获取提现记录的总数
    Integer preWCount = withDrawMapper.selectCountByUserId(user.getUserId());
    int isFirst = preWCount >0 ? 0:1;

//    try {
//
//      boolean flag = false;
//      //获取所有的提现记录
//      if (preWCount > 0) {
//
//        List<WithDraw> withDraws = withDrawMapper.selectWithDrawByUserId(user.getUserId());
//        logger.debug("withDraws is : {}",withDraws);
//        //判断提现状态是否都为驳回
//        for (WithDraw withDraw1 : withDraws) {
//
//          if (withDraw1.getStatus() != 3) {
//            flag = false;
//            break;
//          }
//          if (withDraw1.getStatus() == 3){
//            flag = true;
//            break;
//          }
//        }
//      }
//
//      if (flag) {
//        isFirst = 1;
//      }
//
//    }catch (Exception e){
//      e.printStackTrace();
//    }
    logger.debug("isFirst is : {}",isFirst);

    withDraw.setUserName(user.getUserNickName());
    withDraw.setRealName(user.getRealName());
    withDraw.setPhone(user.getPhone());
    withDraw.setStatus(status);
    withDraw.setType(type);
    withDraw.setAccount(user.getAlipayAccount());
    withDraw.setApplyTime(new Date());
    withDraw.setCommitTime(new Date());
    withDraw.setIsFirst(isFirst);
    logger.debug("withdraw is : {}",withDraw);
    withDrawMapper.insertWithDraw(withDraw);
    logger.debug("插入成功");
  }

  @Override
  public UserWithdrawResponse selectWithDrawDetailForCustomer(Long userId) {

    User user = userMapper.selectById(userId);
    logger.debug("user is : {}", user);
    UserMiddleModel userWithDrawDetail = withDrawMapper.selectWithDrawDetailForCustomer(userId);
    UserMiddleModel userSettlementingDetail = userIncomeMapper.selectSettlementingInfo(userId);

    userWithDrawDetail = userWithDrawDetail == null ? new UserMiddleModel() : userWithDrawDetail;
    userSettlementingDetail = userSettlementingDetail == null ? new UserMiddleModel() : userSettlementingDetail;

    logger.debug("userWithDrawDetail is : {}", userWithDrawDetail);
    logger.debug("userSettlementingDetail is : {}", userSettlementingDetail);

    UserWithdrawResponse userWithdrawResponse = new UserWithdrawResponse();
    // 提现中的集分宝个数
    Long uitOnGoing = DecimalUtil.convertMoneyToUit(userWithDrawDetail.getWithdrawUITOnGoing());
    userWithdrawResponse.setWithdrawUITOnGoing(uitOnGoing);
    // 提现中余额
    userWithdrawResponse.setWithdrawAMOnGoing(userWithDrawDetail.getWithdrawAMOnGoing());
    // 待结算集分宝个数
    Long uitSettlementing = DecimalUtil.convertMoneyToUit(userSettlementingDetail.getWithdrawUITSettlementing());
    userWithdrawResponse.setWithdrawUITSettlementing(uitSettlementing);
    // 待结算金额
    userWithdrawResponse.setWithdrawAMSettlementing(userSettlementingDetail.getWithdrawAMSettlementing());
    logger.debug("userResponseResult is : {}", userWithdrawResponse);
    // 收入金额
    userWithdrawResponse.setUserAmount(
        user.getUserAmount().toString());
    // 集分宝总数
    userWithdrawResponse.setUserIntgeralTreasure(user.getUserIntgeralTreasure());

    return userWithdrawResponse;
  }

  private UserIncome buildUserIncome(WithDraw withDraw){
    UserIncome userIncome = new UserIncome();
    String nowStr = DateUtil.getNowStr();
    userIncome.setCreateTime(nowStr);
    userIncome.setType(UserIncomeConstant.WITHDRAW_EXAMINE_TYPE);
    userIncome.setMoney(withDraw.getMoney());
    if (withDraw.getType() == 0){
      userIncome.setAwardType(UserIncomeConstant.MONEY_AWARD_TYPE);
    }
    if (withDraw.getType() == 1){
      userIncome.setAwardType(UserIncomeConstant.UIT_AWARD_TYPE);
    }
    userIncome.setUserId(withDraw.getUserId());
    return userIncome;
  }

}
